﻿using AutoMapper;
using Castle.Core.Internal;
using SXFramWork.Core;
using SXFramWork.Core.Extension;
using SXFramWork.Model;
using SXFramWork.Repository;
using SXFramWork.Service.Admin.AuthService.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SXFramWork.Service
{
    public class AuthService : IAuthService
    {
        private readonly AppConfig _appConfig;
        private readonly ICache _cache;
        private readonly ISysUserRepository _userRepository;
        private readonly IMapper _mapper;
        private readonly JwtConfig _jwtConfig;
        private readonly ISysAuthInfoRepository _authInfoRepository;
        private readonly VerifyCodeHelper _verifyCode;
        private readonly ILoginInfo _loginInfo;
        private readonly ISysPermissionRepository _permissionRepository;
        private readonly ISysUserConfigRepository _userConfigRepository;
        private readonly ISysMessageService _msgService;
        private readonly ISysUserRoleRepository _sysUserRoleRepository;

        public AuthService(AppConfig appConfig,ICache cache,ISysUserRepository sysUserRepository,IMapper mapper,JwtConfig jwtConfig,ISysAuthInfoRepository authInfoRepository,VerifyCodeHelper verifyCodeHelper,ILoginInfo loginInfo,ISysPermissionRepository sysPermissionRepository,ISysUserConfigRepository sysUserConfigRepository,ISysMessageService sysMessageService,ISysUserRoleRepository sysUserRoleRepository)
        {
            _sysUserRoleRepository = sysUserRoleRepository;
            _msgService = sysMessageService;
            _userConfigRepository = sysUserConfigRepository;
            _permissionRepository = sysPermissionRepository;
            _loginInfo = loginInfo;
            _verifyCode = verifyCodeHelper;
            _authInfoRepository = authInfoRepository;
            _jwtConfig = jwtConfig;
            _mapper = mapper;
            _userRepository = sysUserRepository;
            _cache = cache;
            _appConfig = appConfig;
        }

        public IApiResult CreateVerifyCode(int length)
        {
            var model = new 
            {
                Id = Guid.NewGuid(),
                Base64String = _verifyCode.DrawVerifyCodeBase64String(out string code, length)
            };

            var key = string.Format(CacheKey.VerifyCodeKey, model.Id);

            //把验证码放到内存缓存中，有效期10分钟
            _cache.SetAsync(key, code, 10);
            return ApiResult.Ok(model);
        }
        /// <summary>
        /// 获得认证信息
        /// </summary>
        /// <returns></returns>
        public async Task<IApiResult> GetAuthInfo()
        {
            if (_loginInfo.UserId.Length<=0)
            {
                return ApiResult.NotOk("未登录！");
            }

            var user = await _userRepository.GetAsync(_loginInfo.UserId);
            if (user == null)
                return ApiResult.NotOk("账户不存在");
            if (user.Status == 0)
                return ApiResult.NotOk("账户未启用");

            var model = new AuthInfoOutPut
            {
                 Adress=user.Adress,
                 CreateTime=user.CreateTime,
                 Sex=user.Sex,
                 HeadPic=user.HeadPic,
                 Id=user.Id,
                 Password=user.Password,
                 Phone=user.Phone,
                 Remarks=user.Remarks,
                 TrueName=user.TrueName,
                 UpLoginDate=user.UpLoginDate,
                 UserName=user.UserName
            };

            var entities = new List<SysPermissionEntity>();
         
            if (!_loginInfo.RoleName.Contains("超级管理员"))
            {
                entities = await _permissionRepository.GetMenuAsync(user.Id);
                model.Permissions= await _permissionRepository.GetPermissionByUId(user.Id);
            }
            else
            {
                //如果当前是超级管理员，默认赋予全部权限
                entities = await _permissionRepository.GetAllMenus();
                model.Permissions = await _permissionRepository.GetPermission();
            }

            //菜单列表   
            var all = _mapper.Map<List<UserMenu>>(entities);
            //var tree = all.Where(e => e.ParentId.IsNull()).OrderBy(e => e.Sort).ToList();

            //tree.ForEach(menu =>
            //{
            //    SetChildren(menu, all);
            //});
            model.Menus = all;
            foreach(var item in model.Menus)
            {
                item.NamePath = item.Name;
            }

            //账户Web系统配置config

            var config = await _userConfigRepository.GetByUserIdAsync(user.Id);
            model.config = config;

            var msgList = await _msgService.GetUnReadList();
            model.MsgCount = msgList.Count;
            //未读消息的条数
            return ApiResult.Ok(model);
        }


        private  void  SetChildren(UserMenu parent, List<UserMenu> all)
        {
            parent.Children = all.Where(e => e.ParentId == parent.Id).OrderBy(e => e.Sort).ToList();

            if (parent.Children.Any())
            {
                foreach (var item in parent.Children)
                {
                    item.NamePath = Task.Run(()=> SqlHelper.getstrasync(@"with tb as
                    (
                    select * from SysPermission where id=@0
                    union all
                    select a.* from SysPermission a join tb b on a.id=b.ParentId where b.ParentId is not null and b.ParentId <>''
                    ) 
                    select STUFF((select '/'+name from tb order by tb.Layer asc for xml path('')),1,1,'')", null, item.Id)).Result;
                }
                parent.Children.ForEach(menu =>
                {
                    SetChildren(menu, all);
                });
            }
        }
        public async Task<ApiResult<LoginOutPut>> LoginAsync(LoginInput model)
        {
            var result = new ApiResult<LoginOutPut>();
            //验证码
            if (_appConfig.VerifyCode)
            {
                if (model.VerifyCode.IsNull())
                    return result.NotOk("请输入验证码！");

                var verifyCodeKey = string.Format(CacheKey.VerifyCodeKey, model.VerifyCodeId);
                var exists = await _cache.ExistsAsync(verifyCodeKey);
                if (exists)
                {
                    var verifyCode = await _cache.GetAsync(verifyCodeKey);
                    if (string.IsNullOrEmpty(verifyCode))
                    {
                        return result.NotOk("验证码已过期！");
                    }
                    if (verifyCode.ToLower() != model.VerifyCode.ToLower())
                    {
                        return result.NotOk("验证码输入有误！");
                    }
                    await _cache.RemoveAsync(verifyCodeKey);
                }
                else
                {
                    return result.NotOk("验证码已过期！");
                }
            }
            //账号和密码验证
            var user=  await _userRepository.GetUserByNameAsync(model.UserName);
            var roles = await _sysUserRoleRepository.QueryRole(user.Id);
            user.Roles = string.Join(",", roles.Where(a =>a.Selected==true).Select(t => t.Name).Distinct().ToArray());

            if (user == null)
                return result.NotOk("账户不存在！");
            //未激活
            if(user.Status==0)
                return result.NotOk("账户未激活！");

            if (!user.Password.Equals(Md5Encrypt.Encrypt(model.Password)))
            {
                return result.NotOk("密码错误！");
            }
            //更新认证信息并返回结果 往authinfo表插入或更新数据
            var resultModel = await UpdateAuthInfo(user, model, _jwtConfig);
            return resultModel != null ? result.Ok(resultModel,"登录成功！") : result.NotOk();
        }

        public async Task<ApiResult<LoginOutPut>> RefreshToken(string refreshToken)
        {
            var result = new ApiResult<LoginOutPut>();
            var cacheKey = string.Format(CacheKey.AUTH_REFRESH_TOKEN, refreshToken);
            if (!_cache.TryGetValue(cacheKey, out SysAuthInfoEntity authInfo))
            {
                authInfo = await _authInfoRepository.GetByRefreshToken(refreshToken);
                if (authInfo == null)
                    return result.NotOk("身份认证信息无效，请重新登录~");

                //加入缓存
                var expires = (int)(authInfo.RefreshTokenExpiredTime - DateTime.Now).TotalMinutes;
                await _cache.SetAsync(cacheKey, authInfo, expires);
            }

            if (authInfo.RefreshTokenExpiredTime <= DateTime.Now)
                return result.NotOk("身份认证信息过期，请重新登录~");

            var user = await _userRepository.GetAsync(authInfo.SysUserId);
            var roles= await _sysUserRoleRepository.QueryRole(authInfo.SysUserId);
            user.Roles = string.Join(",", roles.Where(a =>a.Selected==true).Select(t => t.Name).Distinct().ToArray());


            if (user == null)
                return result.NotOk("账户不存在！");
            //未激活
            if (user.Status == 0)
                return result.NotOk("账户未激活！");
            return result.Ok(new LoginOutPut
            {
                User = user,
                AuthInfo = authInfo
            });
        }

        /// <summary>
        /// 生成刷新令牌
        /// </summary>
        /// <returns></returns>
        private string GenerateRefreshToken()
        {
            return Guid.NewGuid().ToString().Replace("-", "");
        }
        /// <summary>
        /// 更新账户认证信息
        /// </summary>
        private async Task<LoginOutPut> UpdateAuthInfo(SysUserEntity user, LoginInput model, JwtConfig config)
        {
            var authInfo = new SysAuthInfoEntity
            {
                SysUserId = user.Id,
                LoginTime = DateTime.Now.ToTimestamp(),
                RefreshToken = GenerateRefreshToken(),
                RefreshTokenExpiredTime = DateTime.Now.AddMinutes(config.RefreshExpires)
            };
            //设置过期时间
            if (config.RefreshExpires > 0)
            {
                authInfo.RefreshTokenExpiredTime = DateTime.Now.AddMinutes(config.RefreshExpires);
            }

            Task<bool> task = null;
            Task<string> task2=null;
            var entity = await _authInfoRepository.GetByUserIdAsync(user.Id);

            string res2 = string.Empty;
            if (entity != null)
            {
                authInfo.Id = entity.Id;
                task = _authInfoRepository.UpdateAsync(authInfo);
            }
            else
            {
                task2 = _authInfoRepository.InsertAsync(authInfo);
                res2= await task2;
            }
            var res3 = false;
            if (task != null)
            {
                 res3 = await task;
            }
           
            if ((res3)||(!res2.IsNull()))
            {
                //判断是否开启验证码功能，删除验证码缓存
                if (_appConfig.VerifyCode)
                {
                    await _cache.RemoveAsync(string.Format(CacheKey.VerifyCodeKey,model.VerifyCodeId));
                }
                return new LoginOutPut
                {
                    User = user,
                    AuthInfo = authInfo
                };
            }

            return null;
        }

        public async Task<IApiResult> Settheme(string skin)
        {
            var flag=await _userConfigRepository.ExistsAsync (_loginInfo.UserId, "sysuserconfig", "SysUserId");
            if (flag)
            {
                await _userConfigRepository.UpdateConfig(_loginInfo.UserId, skin);
            }
            else
            {
                var entity = new SysUserConfigEntity();
                entity.SysUserId = _loginInfo.UserId;
                entity.Skin = skin;
                await _userConfigRepository.InsertAsync(entity);
            }
            return ApiResult.Ok();
        }
    }
}
